﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using CommonLibrary;
using CommonLibrary.ConfigurationManager;
using CommonLibrary.Exceptions;
using CommonLibrary.Helpers;
using ConnectionManager;
using GalaSoft.MvvmLight.Command;
using InputManager;
using SmartController.Views;

namespace SmartController.ViewModels
{
    public class MainWindowViewModel : ViewModel
    {
        #region Proprieties

        #region Context
        private readonly IAppContext _context;
        private readonly IConnectionManager _connectionManager;
        private readonly RawInputManager _inputManager;

        private OutputWindow _outputWindow;
        #endregion

        #region Profile and Config

        private List<string> _profiles;
        public List<string> Profiles
        {
            get { return _profiles ?? (Profiles = ConfigManager.GetAllApplicationProfiles()); }
            set
            {
                _profiles = value;
                SelectedProfile = _profiles.FirstOrDefault();
                OnPropertyChanged("Profiles");
            }
        }

        private List<int> _configs;
        public List<int> Configs
        {
            get { return _configs; }
            set
            {
                _configs = value;
                SelectedConfig = _configs.FirstOrDefault();
                OnPropertyChanged("Configs");
            }
        }

        private string _selectedProfile;
        public string SelectedProfile
        {
            get { return _selectedProfile; }
            set
            {
                _selectedProfile = value;
                _context.GetApplicationProfile(value);
                Configs = _context.ProcessedProfile.Configs.Select(p => p.Id).ToList();
                OnPropertyChanged("SelectedProfile");
            }
        }

        private int _selectedConfig;
        public int SelectedConfig
        {
            get { return _selectedConfig; }
            set
            {
                _selectedConfig = value;
                _context.GetApplicationProfile(SelectedProfile, value);
                OnPropertyChanged("SelectedConfig");
            }
        }

        #endregion

        #region Com Ports
        public int PoolRate
        {
            get
            {
                return _context.GlobalConfig.SerialPortConfig.PoolRate;
            }
            set { _context.GlobalConfig.SerialPortConfig.PoolRate = value; }
        }

        private List<string> _comPorts;
        public List<string> ComPorts
        {
            get { return _comPorts ?? (ComPorts = _connectionManager.GetSerialPorts()); }
            set
            {
                _comPorts = value;
                OnPropertyChanged("ComPorts");
                SelectedComPort = ComPorts.FirstOrDefault();
            }
        }

        private string _selectedComPort;
        public string SelectedComPort
        {
            get { return _selectedComPort; }
            set
            {
                _selectedComPort = value;
                _context.GlobalConfig.SerialPortConfig.PortName = value;
            }
        }

        #endregion

        #region Button Text & Ui status

        private string _connectionStatus;
        public string ConnectionStatus
        {
            get { return String.IsNullOrWhiteSpace(_connectionStatus) ? "Connect" : _connectionStatus; }
            private set { _connectionStatus = value; OnPropertyChanged("ConnectionStatus"); OnPropertyChanged("UIState"); }
        }

        private string _inputStatus;
        public string InputStatus
        {
            get { return String.IsNullOrWhiteSpace(_inputStatus) ? "Pause" : _inputStatus; }
            private set { _inputStatus = value; OnPropertyChanged("InputStatus"); }
        }

        public bool UIState {
            get { return ConnectionStatus.Equals("Connect"); } 
        }

        #endregion

        #endregion

        #region Commands
        public ICommand RefreshComPortsCommand { get; private set; }
        public ICommand ConnectCommand { get; private set; }
        public ICommand PauseOrResumeInputCommand { get; private set; }
        public ICommand WindowClosedCommand { get; private set; }
        public ICommand OpenConfigManagerCommand { get; private set; }
        public ICommand OpenOutputWindowCommand { get; private set; }
        #endregion

        #region Constructor
        public MainWindowViewModel()
        {
            _context = AppContext.Current;

            #region Commands

            RefreshComPortsCommand = new RelayCommand(GetSerialPorts);
            ConnectCommand = new RelayCommand(ConnectDisconnectFromPort, CanConnectDisconnectFromPort);
            PauseOrResumeInputCommand = new RelayCommand(PauseOrResume, CanPauseOrResume);
            WindowClosedCommand = new RelayCommand(WindowClosed);
            OpenConfigManagerCommand = new RelayCommand(OpenConfigWindow);
            OpenOutputWindowCommand = new RelayCommand(OpenOutputWindow);

            #endregion

            _connectionManager = ConnectionManagerFactory.GetConnectionManager(ConnectionManagerType.PS3SerialConnection, _context);
            _inputManager = new RawInputManager(_context);
            _inputManager.IsClosing += InputManagerClosed;
        }

        #endregion

        #region Pause / Resume Input Capture and Data Send
        private void PauseOrResume()
        {
            if (InputStatus.Equals("Pause"))
            {
                _inputManager.StopInputCapture();
                _connectionManager.StopDataSend();
                InputStatus = "Resume";
                return;
            }

            _inputManager.StartInputCapture();
            _connectionManager.SendData();
            InputStatus = "Pause";
            return;
        }

        private bool CanPauseOrResume()
        {
            return ConnectionStatus.Equals("Disconect");
        }

        private void InputManagerClosed(object sender, EventArgs e)
        {
            _connectionManager.StopDataSend();
            InputStatus = "Resume";
        }
        #endregion

        #region Serial Port

        private void ConnectDisconnectFromPort()
        {
            if (ConnectionStatus.Equals("Connect"))
            {
                if (!_connectionManager.Connect()) throw new SimpleSmartException("Unable to connect to the port");

                _inputManager.StartInputCapture();

                _connectionManager.SendData();

                ConnectionStatus = "Disconect";

            }
            else
            {
                _connectionManager.Disconnect();

                _inputManager.StopInputCapture();

                ConnectionStatus = "Connect";
            }
        }

        private bool CanConnectDisconnectFromPort()
        {
            return !String.IsNullOrWhiteSpace(SelectedComPort);
        }

        private void GetSerialPorts()
        {
            ComPorts = _connectionManager.GetSerialPorts();
        }

        #endregion

        #region Handle Open/Close Events
        private void WindowClosed()
        {
            _connectionManager.StopDataSend();
            _connectionManager.Disconnect();
            _inputManager.StopInputCapture();
            
            Application.Current.Shutdown();
        }
        #endregion

        #region OutputWindow
        private void OpenOutputWindow()
        {
            if (_outputWindow != null && _outputWindow.IsInitialized)
            {
                _outputWindow.Close();
                _outputWindow = null;
                return;
            }

            _outputWindow = new OutputWindow(_context);
            _outputWindow.Show();
        }
        #endregion

        #region Config Window
        private void OpenConfigWindow()
        {
            // TODO implement config window
        }
        #endregion
    }
}